﻿/**
 * @file text_render.hpp
 * @brief 文本渲染对象
 */
#pragma once
#include "common/unknown_impl.hpp"
#include <wrl.h>
#include <common/Exception.h>
namespace JOUI
{
	class UITextRender : public ExUnknownImpl<IDWriteTextRenderer>
	{
		EX_DECLEAR_INTERFACE_BEGIN();
		EX_DECLEAR_INTERFACE(IUnknown);
		EX_DECLEAR_INTERFACE(IDWriteTextRenderer);
		EX_DECLEAR_INTERFACE_END();

	public:
		UITextRender(ID2D1RenderTarget* target, UIBrush *brush)
		{
			m_target = target;
			target->GetFactory(&m_factory);

			m_fill_brush = (ID2D1Brush*)(brush ? brush->GetContext() : nullptr);
		}
		virtual ~UITextRender()
		{
		}

		virtual HRESULT __stdcall IsPixelSnappingDisabled(void* clientDrawingContext, BOOL* isDisabled) override
		{
			isDisabled = FALSE;
			return S_OK;
		}

		virtual HRESULT __stdcall GetCurrentTransform(void* clientDrawingContext, DWRITE_MATRIX* transform) override
		{
			m_target->GetTransform((D2D1_MATRIX_3X2_F*)transform);
			return S_OK;
		}

		virtual HRESULT __stdcall GetPixelsPerDip(void* clientDrawingContext, float* pixelsPerDip) override
		{
			float tmp = 0;
			m_target->GetDpi(pixelsPerDip, &tmp);
			return S_OK;
		}

		virtual HRESULT __stdcall DrawGlyphRun(void* clientDrawingContext, float baselineOriginX, float baselineOriginY,
			DWRITE_MEASURING_MODE measuringMode, DWRITE_GLYPH_RUN const* glyphRun,
			DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
			IUnknown* clientDrawingEffect) override
		{
			ID2D1PathGeometry* geometry = nullptr;
			ID2D1GeometrySink* sink = nullptr;
			ID2D1TransformedGeometry* transformed_geometry = nullptr;
			Microsoft::WRL::ComPtr<IDWriteColorGlyphRunEnumerator1> glyphRunEnumerator;

			D2D1_POINT_2F baselineOrigin = D2D1::Point2F(baselineOriginX, baselineOriginY);
			DWRITE_GLYPH_IMAGE_FORMATS supportedFormats =
				DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE |
				DWRITE_GLYPH_IMAGE_FORMATS_CFF |
				DWRITE_GLYPH_IMAGE_FORMATS_COLR |
				DWRITE_GLYPH_IMAGE_FORMATS_SVG |
				DWRITE_GLYPH_IMAGE_FORMATS_PNG |
				DWRITE_GLYPH_IMAGE_FORMATS_JPEG |
				DWRITE_GLYPH_IMAGE_FORMATS_TIFF |
				DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8;
			//确定glyphRun中是否有任何颜色的glyph运行。如果有，glyphRunEnumerator可以用来遍历它们。
			g_dwrite_factory4->TranslateColorGlyphRun(
				baselineOrigin,
				glyphRun,
				glyphRunDescription,
				supportedFormats,
				measuringMode,
				nullptr,
				0,
				&glyphRunEnumerator);
			if (glyphRunEnumerator)
			{
				for (;;)
				{
					BOOL haveRun;
					glyphRunEnumerator->MoveNext(&haveRun);
					if (!haveRun)
						break;
					DWRITE_COLOR_GLYPH_RUN1 const* colorRun;
					glyphRunEnumerator->GetCurrentRun(&colorRun);

					D2D1_POINT_2F currentBaselineOrigin = D2D1::Point2F(
						colorRun->baselineOriginX,
						colorRun->baselineOriginY);
					
					if (colorRun->paletteIndex != 0xFFFF)
						((ID2D1SolidColorBrush*)m_fill_brush)->SetColor(colorRun->runColor);
					// Draw the run with the selected color.
					((ID2D1DeviceContext*)m_target)->DrawGlyphRun(
						currentBaselineOrigin,
						&colorRun->glyphRun,
						colorRun->glyphRunDescription,
						m_fill_brush,
						measuringMode
					);
				}
			}
			if (!glyphRunEnumerator)
			{
				//创建字形路径
				return_if_failed(m_factory->CreatePathGeometry(&geometry));

				//开始描述
				return_if_failed(geometry->Open(&sink));

				//获取字形
				return_if_failed(glyphRun->fontFace->GetGlyphRunOutline(glyphRun->fontEmSize, glyphRun->glyphIndices,
					glyphRun->glyphAdvances, glyphRun->glyphOffsets, glyphRun->glyphCount, glyphRun->isSideways, glyphRun->bidiLevel % 2, sink)
				);
				return_if_failed(sink->Close());
				sink->Release();

				//创建变换至基线的图形
				return_if_failed(m_factory->CreateTransformedGeometry(geometry,
					D2D1::Matrix3x2F::Translation(baselineOriginX, baselineOriginY),
					&transformed_geometry)
				);
				//绘制
				if (m_fill_brush) {
					((ID2D1DeviceContext*)m_target)->FillGeometry(transformed_geometry, m_fill_brush);
				}
				geometry->Release();
				transformed_geometry->Release();
				return S_OK;
			}
			return S_FALSE;
		}

		virtual HRESULT __stdcall DrawUnderline(void* clientDrawingContext, float baselineOriginX, float baselineOriginY,
			DWRITE_UNDERLINE const* underline, IUnknown* clientDrawingEffect) override
		{
			ID2D1RectangleGeometry* geometry = nullptr;
			ID2D1TransformedGeometry* transformed_geometry = nullptr;

			//创建矩形图形(下划线)
			return_if_failed(m_factory->CreateRectangleGeometry(
				D2D1::RectF(0, underline->offset,
					underline->width, underline->offset + underline->thickness
				), &geometry)
			);

			//创建变换至基线的图形
			return_if_failed(m_factory->CreateTransformedGeometry(geometry,
				D2D1::Matrix3x2F::Translation(baselineOriginX, baselineOriginY),
				&transformed_geometry)
			);

			//绘制
			if (m_fill_brush) {
				m_target->FillGeometry(transformed_geometry, m_fill_brush);
			}
			geometry->Release();
			transformed_geometry->Release();
			return S_OK;
		}

		virtual HRESULT __stdcall DrawStrikethrough(void* clientDrawingContext, float baselineOriginX, float baselineOriginY,
			DWRITE_STRIKETHROUGH const* strikethrough, IUnknown* clientDrawingEffect) override
		{
			ID2D1RectangleGeometry* geometry = nullptr;
			ID2D1TransformedGeometry* transformed_geometry = nullptr;

			//创建矩形图形(删除线)
			return_if_failed(m_factory->CreateRectangleGeometry(
				D2D1::RectF(0, strikethrough->offset, strikethrough->width, strikethrough->offset + strikethrough->thickness),
				&geometry)
			);

			//创建变换至基线的图形
			return_if_failed(m_factory->CreateTransformedGeometry(geometry,
				D2D1::Matrix3x2F::Translation(baselineOriginX, baselineOriginY),
				&transformed_geometry)
			);

			//绘制
			if (m_fill_brush) {
				m_target->FillGeometry(transformed_geometry, m_fill_brush);
			}
			geometry->Release();
			transformed_geometry->Release();
			return S_OK;
		}

		virtual HRESULT __stdcall DrawInlineObject(void* clientDrawingContext, float originX, float originY,
			IDWriteInlineObject* inlineObject, BOOL isSideways, BOOL isRightToLeft, IUnknown* clientDrawingEffect) override
		{
			return inlineObject->Draw(clientDrawingContext, this, originX, originY, isSideways,
				isRightToLeft, clientDrawingEffect);
		}

	private:
		ID2D1Factory* m_factory = nullptr;
		ID2D1Brush* m_fill_brush = nullptr;
		ID2D1RenderTarget* m_target = nullptr;
	};

	class ExTextFigureBuilderD2D : public ExUnknownImpl<IDWriteTextRenderer>
	{
		EX_DECLEAR_INTERFACE_BEGIN();
		EX_DECLEAR_INTERFACE(IUnknown);
		EX_DECLEAR_INTERFACE(IDWriteTextRenderer);
		EX_DECLEAR_INTERFACE_END();

	public:
		ExTextFigureBuilderD2D(ID2D1Factory* factory, ID2D1GeometrySink* sink)
		{
			m_factory = factory;
			m_sink = sink;
			throw_if_failed(
				factory->CreateRectangleGeometry(D2D1::RectF(), &m_geometry),
				L"创建临时几何形失败"
			);
		}

		virtual ~ExTextFigureBuilderD2D()
		{
		}

		virtual HRESULT __stdcall IsPixelSnappingDisabled(void* clientDrawingContext, BOOL* isDisabled) override
		{
			isDisabled = FALSE;
			return S_OK;
		}

		virtual HRESULT __stdcall GetCurrentTransform(void* clientDrawingContext, DWRITE_MATRIX* transform) override
		{
			*transform = DWRITE_MATRIX{
				1.0F,0.0F,
				0.0F,1.0F,
				0.0F,0.0F
			};
			return S_OK;
		}

		virtual HRESULT __stdcall GetPixelsPerDip(void* clientDrawingContext, float* pixelsPerDip) override
		{
			*pixelsPerDip = _SYS_DEFAULT_DPI;
			return S_OK;
		}

		virtual HRESULT __stdcall DrawGlyphRun(void* clientDrawingContext, float baselineOriginX, float baselineOriginY,
			DWRITE_MEASURING_MODE measuringMode, DWRITE_GLYPH_RUN const* glyphRun,
			DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
			IUnknown* clientDrawingEffect) override
		{
			ID2D1PathGeometry* geometry = nullptr;
			ID2D1GeometrySink* sink = nullptr;
			ID2D1TransformedGeometry* transformed_geometry = nullptr;
			HRESULT hr = 0;
			//创建字形路径
			return_if_failed(m_factory->CreatePathGeometry(&geometry));

			//开始描述
			return_if_failed(geometry->Open(&sink));

			//获取字形
			return_if_failed(glyphRun->fontFace->GetGlyphRunOutline(glyphRun->fontEmSize, glyphRun->glyphIndices,
				glyphRun->glyphAdvances, glyphRun->glyphOffsets, glyphRun->glyphCount, glyphRun->isSideways,
				glyphRun->bidiLevel != 0, sink)
			);
			return_if_failed(sink->Close());
			sink->Release();

			//与临时几何形合并
			hr = m_geometry->CombineWithGeometry(
				geometry, D2D1_COMBINE_MODE_UNION,
				D2D1::Matrix3x2F::Translation(baselineOriginX, baselineOriginY),
				m_sink
			);
			 geometry->Release();
			 transformed_geometry->Release();
			 return hr;
		}

		virtual HRESULT __stdcall DrawUnderline(void* clientDrawingContext, float baselineOriginX, float baselineOriginY,
			DWRITE_UNDERLINE const* underline, IUnknown* clientDrawingEffect) override
		{
			ID2D1RectangleGeometry* geometry = nullptr;
			ID2D1TransformedGeometry* transformed_geometry = nullptr;
			HRESULT hr = 0;
			//创建矩形图形(下划线)
			return_if_failed(m_factory->CreateRectangleGeometry(
				D2D1::RectF(0, underline->offset,
					underline->width, underline->offset + underline->thickness
				), &geometry)
			);

			//与临时几何形合并
			hr = m_geometry->CombineWithGeometry(
				geometry, D2D1_COMBINE_MODE_UNION,
				D2D1::Matrix3x2F::Translation(baselineOriginX, baselineOriginY),
				m_sink
			);
			geometry->Release();
			transformed_geometry->Release();
			return hr;
		}

		virtual HRESULT __stdcall DrawStrikethrough(void* clientDrawingContext, float baselineOriginX, float baselineOriginY,
			DWRITE_STRIKETHROUGH const* strikethrough, IUnknown* clientDrawingEffect) override
		{
			ID2D1RectangleGeometry* geometry = nullptr;
			ID2D1TransformedGeometry* transformed_geometry = nullptr;
			HRESULT hr = 0;
			//创建矩形图形(删除线)
			return_if_failed(m_factory->CreateRectangleGeometry(
				D2D1::RectF(0, strikethrough->offset, strikethrough->width, strikethrough->offset + strikethrough->thickness),
				&geometry)
			);

			//与临时几何形合并
			hr = m_geometry->CombineWithGeometry(
				geometry, D2D1_COMBINE_MODE_UNION,
				D2D1::Matrix3x2F::Translation(baselineOriginX, baselineOriginY),
				m_sink
			);
			geometry->Release();
			transformed_geometry->Release();
			return hr;
		}

		virtual HRESULT __stdcall DrawInlineObject(void* clientDrawingContext, float originX, float originY,
			IDWriteInlineObject* inlineObject, BOOL isSideways, BOOL isRightToLeft, IUnknown* clientDrawingEffect) override
		{
			return E_NOTIMPL;
		}

	private:
		ID2D1Factory* m_factory;
		ID2D1RectangleGeometry* m_geometry;
		ID2D1GeometrySink* m_sink;
	};

}
